<?php
/**
 * Created by PhpStorm.
 * User: bobo
 * Date: 17-12-22
 * Time: 上午10:25
 */

namespace WsdServer;

use Illuminate\Cache\CacheManager;
use Illuminate\Container\Container;
use Illuminate\Redis\Database;
use Illuminate\Database\Capsule\Manager as Capsule;
use Illuminate\Events\Dispatcher;

use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Configuration AS DoctrineConfig;
use Doctrine\DBAL\Logging\DebugStack;
use Doctrine\DBAL\Logging\EchoSQLLogger;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;

use Server\Components\Backstage\BackstageProcess;
use Server\Components\CatCache\CatCacheProcess;
use Server\Components\Cluster\ClusterProcess;
use Server\Components\Process\ProcessManager;
use Server\Components\SDHelp\SDHelpProcess;
use Server\SwooleDistributedServer;
use WsdServer\Asyn\AMQP\AmqpAsynPool;
use WsdServer\Components\Consul\WsdConsulProcess;


abstract class WsdSwooleDistributedServer extends SwooleDistributedServer
{
    /**
     * @var AmqpAsynPool
     */
    public $amqp_pool;

    // Add by hb on 2018-01-03 for Support Doctrine-ORM
    private $doctrine_db_conn;
    private $doctrine_db_em;

    // Add by hb on 2018-04-03 for Support Laravel-Eloquent
    private $laravelCache;
    private $laravelDatabase;
    private $laravelDBConnect;

    /**
     * 创建用户进程
     * Add by hb on 2017-12-22: 完全覆盖重写SwooleDistributedServer::startProcess()
     */
    public function startProcess()
    {
        //timerTask,reload进程
        ProcessManager::getInstance()->addProcess(SDHelpProcess::class, false);
        //consul进程
        if ($this->config->get('consul.enable', false)) {
            // Modify by hb on 2017-12-22: 用 WsdConsulProcess 替换 ConsulProcess
            //ProcessManager::getInstance()->addProcess(ConsulProcess::class, false);
            ProcessManager::getInstance()->addProcess(WsdConsulProcess::class, false);
        }
        if ($this->config->get('backstage.enable', false)) {
            ProcessManager::getInstance()->addProcess(BackstageProcess::class, false);
        }
        //Cluster进程
        ProcessManager::getInstance()->addProcess(ClusterProcess::class);
        //CatCache进程
        if ($this->config->get('catCache.enable', false)) {
            ProcessManager::getInstance()->addProcess(CatCacheProcess::class, false);
        }
    }


    /**
     * 初始化各种连接池，添加异步amqp
     * @param $workerId
     * @throws \Server\CoreBase\SwooleException
     */
    public function initAsynPools($workerId)
    {
        parent::initAsynPools($workerId);

        if ($this->config->get('amqp.publish.enable', false)) {
            $amqpAsynPool = new AmqpAsynPool($this->config, $this->config->get('amqp.active'));
            $this->addAsynPool('amqpPool', $amqpAsynPool);
        }

        // Add by hb on 2018-01-03 for Support Doctrine-ORM
        if ($this->config->get('mysql.doctrine.enable', false)) {
            try {
                $isDevMode = true;

                //$config = new DoctrineConfig();

                /*
                $paths = array(ORM_ANNOTATION_DIR);
                //$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
                $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
                */

                $paths = array(ORM_XML_DIR);
                $config = Setup::createXMLMetadataConfiguration($paths, $isDevMode);

                /*
                $paths = array(ORM_YAML_DIR);
                $config = Setup::createYAMLMetadataConfiguration($paths, $isDevMode);
                */

                $config->setSQLLogger(new DebugStack());

                $activeConfig = $this->config['mysql'][$this->config['mysql']['active']];
                $connectionParams = array(
                    'driver' => 'pdo_mysql',
                    'host' => $activeConfig['host'],
                    'pot' => $activeConfig['port'],
                    'user' => $activeConfig['user'],
                    'password' => $activeConfig['password'],
                    'dbname' => $activeConfig['database'],
                    'charset' => $activeConfig['charset'],
                    'wrapperClass' => 'WsdServer\Lib\PDO\WsdConnection'
                );
                $this->doctrine_db_conn = DriverManager::getConnection($connectionParams, $config);
                $this->doctrine_db_em = EntityManager::create($connectionParams, $config);
            } catch (\Exception $e) {
                secho("WsdSwooleDistributedServer::initAsynPools", $e->getMessage());
            }
        }

        // Add by hb on 2018-04-03 for Support Laravel-Cache
        $container = new Container;
        $container['config'] = [
            'cache.default' => 'redis',
            'cache.stores.redis' => [
                'driver' => 'redis',
                'connection' => 'default'
            ],
            'cache.prefix' => 'laravel',
            'database.redis' => [
                'cluster' => false,
                'default' => [
                    'host' => $this->config->get('redis.cache.ip', '127.0.0.1'),
                    'port' => $this->config->get('redis.cache.port', 6379),
                    'database' => $this->config->get('redis.cache.select', 0),
                    'password' => $this->config->get('redis.cache.password', ''),
                ],
            ]
        ];
        $container['redis'] = new Database($container['config']['database.redis']);
        $cacheManager = new CacheManager($container);
        // Get the default cache driver (redis in this case)
        $cache = $cacheManager->store();
        // Or if you have multiple drivers configured, you can get the redis store like this:
        // $cache = $cacheManager->store('redis');
        $cache->put('test', 'This is loaded from cache.', 500);
        //echo $cache->get('test');
        $this->laravelCache = $cache;

        // Add by hb on 2018-04-03 for Support Laravel-Eloquent
        $capsule = new Capsule;
        $capsule->addConnection([
            'driver'    => 'mysql',
            'host'      => $this->config->get('mysql.laravel.host', '127.0.0.1'),
            'database'  => $this->config->get('mysql.laravel.database', 'omg'),
            'username'  => $this->config->get('mysql.laravel.user', 'omg'),
            'password'  => $this->config->get('mysql.laravel.password', 'omg'),
            'charset'   => $this->config->get('mysql.laravel.charset', 'utf8'),
            'collation' => $this->config->get('mysql.laravel.collation', 'utf8_unicode_ci'),
            'prefix'    => $this->config->get('mysql.laravel.prefix', '')
        ]);
        // Set the event dispatcher used by Eloquent models... (optional)
        $capsule->setEventDispatcher(new Dispatcher(new Container));
        // Make this Capsule instance available globally via static methods... (optional)
        $capsule->setAsGlobal();
        // Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
        $capsule->bootEloquent();

        $this->laravelDBConnect = $capsule->getConnection('default');
        //secho("init", $this->laravelDBConnect);

        $this->laravelDatabase = $capsule;
    }

    public function getLaravelCache()
    {
        return $this->laravelCache;
    }

    public function getLaravelDatabase()
    {
        return $this->laravelDatabase;
    }

    public function getLaravelDBConnect()
    {
        return $this->laravelDBConnect;
    }

    /**
     * 重写onSwooleWorkerStart方法，添加异步amqp
     * @param $serv
     * @param $workerId
     * @throws \Server\CoreBase\SwooleException
     */
    public function onSwooleWorkerStart($serv, $workerId)
    {
        parent::onSwooleWorkerStart($serv, $workerId);
        $this->amqp_pool = $this->getAsynPool('amqpPool') ?? null;

    }

    /**
     * 开服初始化(支持协程)，添加amqp连接
     * @return mixed
     */
    public function onOpenServiceInitialization()
    {
        if ($this->amqp_pool != null) {
            //$this->amqp_pool->initConnect();
        }
    }

    /**
     * @return mixed
     */
    public function getDoctrineConn()
    {
        return $this->doctrine_db_conn;
    }

    /**
     * @return mixed
     */
    public function getDoctrineEm()
    {
        return $this->doctrine_db_em;
    }
}